//
//  loader.h
//  Source
//
//  Created by Toj on 6/27/23.
//

#ifndef loader_h
#define loader_h

#include <stdio.h>

// MARK: -【MachO文件Header.jpeg】
// mach_header忽略了, 根mach_header_64 差一个reserved保留字段
struct mach_header_64 {
    // 判断程序的平台版本.
    // MHMAGIC是一个宏, 有2个值表示不同架构
    // 如果是0xFEEDFACE 就是x86程序
    // 如果是0xFEEDFACF 就是x64程序
    uint32_t magic;
    
    // 判断CPU的平台与版本.
    // 在mach/machine.h 头文件中可以看到两组宏定义
    // CPUTYPE、 CPUSUBTYPE 定义着各种各样的型号
    cpu_type_t cputype;
    cpu_subtype_t cpusubtype;
    // 判断程序的文件类型,
    // 在mach-o/loader.h 中定义一组宏可以很直观的明白该位的意义
    uint32_t filetype;
    // Load Command的个数
    uint32_t ncmds; // 全称: number of load commands
    // ncmds段Load Command的总字节数
    uint32_t sizeofcmds;
    // dyld加载标志位
    // 它的标识宏在mach-o/loader.h中格式为MH_???
    uint32_t flags;
    // reserved是x64的保留位, 目前看了下基本是恒为0x00000000
    uint32_t reserved;
};

// MARK: filetype

/* 编译过程中产生的*.obj文件 */
#define    MH_OBJECT       0x1  // gcc -c xxx.c 生成xxx.o文件
/* 可执行二进制文件 */
#define    MH_EXECUTE      0x2
/* 固定虚拟机共享库文件 */
#define    MH_FVMLIB       0x3
/* 崩溃时的Dump文件 */
#define    MH_CORE         0x4
/* 预加载的可执行文件 */
#define    MH_PRELOAD      0x5
/* 动态库 */
#define    MH_DYLIB        0x6 // /usr/lib/里面的那些库文件
/* 动态链接器 */
#define    MH_DYLINKER     0x7  // /usr/lib/dyld文件
/* 动态绑定包文件 */
#define    MH_BUNDLE       0x8
/* 共享的静态库 */
#define    MH_DYLIB_STUB   0x9

/*  linking only, no section contents */
/* 只有调试的配套文件 */
#define    MH_DSYM         0xa
/*  sections */
/* 内核扩展文件 */
#define    MH_KEXT_BUNDLE  0xb

// MARK: flags
MH_NOUNDEFS               目标没有未定义的符号，不存在链接依赖
MH_DYLDLINK               该目标文件是dyld的输入文件，无法被再次的静态链接
MH_PIE                    允许随机的地址空间
MH_ALLOW_STACK_EXECUTION  栈内存可执行代码，一般是默认关闭的。
MH_NO_HEAP_EXECUTION      堆内存无法执行代码

// MARK: - Load Commands

struct load_command {
    // cmd该位的值表示类型
    // mach-o/loader.h中定义loadcommand结构体的下方有着一组宏, 不同类型对应不同的的结构
    uint32_t cmd;
    // cmdsize该位代表所占字节数
    uint32_t cmdsize;
};

/*
segment_command          LC_SEGMENT
segment_command_64       LC_SEGMENT_64
fvmlib_command           LC_IDFVMLIB or LC_LOADFVMLIB
dylib_command            LC_ID_DYLIB, LC_LOAD_{,WEAK_}DYLIB, LC_REEXPORT_DYLIB`
sub_framework_command    LC_SUB_FRAMEWORK
sub_client_command       LC_SUB_CLIENT`
sub_umbrella_command     LC_SUB_UMBRELLA
sub_library_command      LC_SUB_LIBRARY
prebound_dylib_command   LC_PREBOUND_DYLIB
dylinker_command         LC_ID_DYLINKER, LC_LOAD_DYLINKER orLC_DYLD_ENVIRONMENT
thread_command           LC_THREAD or  LC_UNIXTHREAD
routines_command         LC_ROUTINES
symtab_command           LC_SYMTAB
dysymtab_command         LC_DYSYMTAB
twolevel_hints_command   LC_TWOLEVEL_HINTS
prebind_cksum_command    LC_PREBIND_CKSUM
uuid_command             LC_UUID
rpath_command            LC_RPATH
linkedit_data_command    LC_CODE_SIGNATURE,
                         LC_SEGMENT_SPLIT_INFO,
                         LC_FUNCTION_STARTS,
                         LC_DATA_IN_CODE,
                         LC_DYLIB_CODE_SIGN_DRS
                         LC_LINKER_OPTIMIZATION_HINT.
 
encryption_info_command  LC_ENCRYPTION_INFO
version_min_command      LC_VERSION_MIN_MACOSX
                         LC_VERSION_MIN_IPHONEOS
                         LC_VERSION_MIN_WATCHOS
 
dyld_info_command        LC_DYLD_INFO or LC_DYLD_INFO_ONLY
linker_option_command    LC_LINKER_OPTION
symseg_command           LC_SYMSEG
ident_command            LC_IDENT
fvmfile_command          LC_FVMFILE
entry_point_command      LC_MAIN
source_version_command   LC_SOURCE_VERSION
*/

// MARK: LC_SEGMENT_64 __DATA段
/**
 * 段内详细数据请看:【LC_SEGMENT_64-DATA.png】
 ** DATA段的数量就是Load Command中secetion的总数量
 * 按理说也是外层下面Section64的数量, 不过对不上缺少2个【__bss & __common】
 * 相应的数据与大小就是addr起始的size字节大小的数据
 * 每一个Section的 offset 就对应该DATA段的首地址 size也是该段的大小
 */

struct section_64 {
    char sectname[16];
    char segname[16];
    uint64_t addr;
    uint64_t size;
    uint32_t offset;
    uint32_t align;
    uint32_t reloff;
    uint32_t nreloc;
    uint32_t flags;
    uint32_t reserved1;
    uint32_t reserved2;
    uint32_t reserved3;
};

//
/**
 * NOTE: 不同的Section有着不同的作用就可以
 * 1. __text: 代码段
 * 1. __cstring: 硬编码的字符串
 * 1. __const: 关键词修饰过的变量
 * 1. __bss: bss段
 * 1. __common: common段
 */
   

#endif /* loader_h */
